package org.zachary.creditbusiness.hotel.util;

import com.github.signaflo.timeseries.TimeSeries;
import com.github.signaflo.timeseries.forecast.Forecast;
import com.github.signaflo.timeseries.model.arima.Arima;
import com.github.signaflo.timeseries.model.arima.ArimaOrder;
import org.apache.commons.csv.CSVFormat;
import org.apache.commons.csv.CSVParser;
import org.apache.commons.csv.CSVRecord;

import java.io.Reader;
import java.nio.charset.StandardCharsets;
import java.nio.file.*;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.*;

/**
 * 酒店入住率预测工具 —— 不再序列化模型，每次都重新训练
 */
public class OccupancyPredictionUtil {

    private static final DateTimeFormatter DATE_ONLY_FMT =
            DateTimeFormatter.ofPattern("yyyy-MM-dd");

    /**
     * 读取 CSV，训练 ARIMA 并预测未来 7 天入住率
     *
     * @param hotelId      酒店 ID，对应 static/hoteldata/{hotelId}/occupancy.csv
     * @param currentDate  当前日期字符串，格式 "yyyy-MM-dd"
     * @param baseDir      classpath:static/hoteldata 的绝对路径
     * @return 按 yyyy-MM-dd 排序的 7 天预测结果
     */
    public static Map<String, Double> occupancyPrediction(
            int hotelId,
            String currentDate,
            String baseDir) throws Exception {

        // 1. 今天
        LocalDate today = LocalDate.parse(currentDate, DATE_ONLY_FMT);

        // 2. CSV 路径
        Path csvPath = Paths.get(baseDir, String.valueOf(hotelId), "occupancy.csv");

        // 3. 读取并过滤数据
        List<Double> values = new ArrayList<>();
        try (Reader reader = Files.newBufferedReader(csvPath, StandardCharsets.UTF_8);
             CSVParser parser = CSVParser.parse(reader,
                     CSVFormat.DEFAULT.withFirstRecordAsHeader().withTrim())) {
            for (CSVRecord rec : parser) {
                LocalDate d = LocalDate.parse(rec.get("time"), DATE_ONLY_FMT);
                if (!d.isAfter(today)) {
                    values.add(Double.parseDouble(rec.get("occupancy")));
                }
            }
        }

        // 4. 模拟 Python 的 df[:-1]
        if (!values.isEmpty()) {
            values.remove(values.size() - 1);
        }

        // 5. 拟合非季节性 ARIMA(1,1,1)
        double[] data = values.stream().mapToDouble(Double::doubleValue).toArray();
        TimeSeries ts = TimeSeries.from(data);
        ArimaOrder order = ArimaOrder.order(1, 1, 1);
        Arima model = Arima.model(ts, order);

        // 6. 预测未来 7 天
        Forecast forecast = model.forecast(7, 0.05);
        double[] preds = forecast.pointEstimates().asArray();

        // 7. 构造结果 Map，从 tomorrow 开始
        Map<String, Double> result = new LinkedHashMap<>();
        for (int i = 0; i < preds.length; i++) {
            LocalDate d = today.plusDays(i + 1);
            result.put(d.format(DATE_ONLY_FMT), preds[i]);
        }
        return result;
    }
}